/*
* Copyright (c) 2020 The canvas Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.

* Author:         dzlua - https://gitee.com/dzlua/canvas.git
* Email:          505544956@qq.com
* FileName:       canvas_2d.h
* Create Time:    2020/01/01 10:12:15
* Description:    /
*/

#ifndef __CANVAS_2D_H__
#define __CANVAS_2D_H__

#include "canvas.h"

namespace cvs {
namespace c2d {
  class IRender;
  class ITarget;
  class IBitmapTarget;
} // end namespace cvs
} // end namespace c2d

namespace cvs {
namespace c2d {
  enum class FigureEnd : uint8 {
    Close, Open
  };

  enum class FillMode : uint8 {
    NoneZero,EvenOdd
  };

  enum class CombineMode : uint8 {
    Union, Intersect, Xor, Exclude
  };

  enum class ExtendMode : uint8 {
    Clamp, Wrap, Mirror
  };

  enum class LineCap : uint8 {
    Flat, Round, Square, Triangle
  };

  enum class LineJoin : uint8 {
    Miter, Bevel, Round
  };

  enum class PixelFormat : uint8 {
    PBGRA32,
  };

  enum class SurfaceType : uint8 {
    Bmp, Jpeg, Png
  };

  enum class ShapeType : uint8 {
    Line, Polyline, Bezier, Arc,
    Polygon, Rect, Circle, Ellipse,
    Path, Text
  };

  enum class TextAlignHor : uint8 {
    Left, Center, Right
  };
  enum class TextAlignVer : uint8 {
    Top, Middle, Bottom
  };
  enum class TextDirection : uint8 {
    LeftToRight, RightToLeft,
    TopToBottom, BottomToTop
  };
  enum class TextTrimming : uint8 {
    None, Clip, Ellipsis
  };

  struct StrokeStyleProperties {
    LineCap startCap;
    LineCap endCap;
    LineCap dashCap;
    LineJoin lineJoin;
    dtype miterLimit;
    dtype dashOffset;
  };

  struct GradientStop {
    dtype pos;
    Color color;
  };
  struct LinearGradientBrushProperties {
    Point start;
    Point end;
  };
  struct RadialGradientBrushProperties {
    Point center;
    Point offset;
    dtype radius_x;
    dtype radius_y;
  };

  struct BezierSegment {
    Point p0;
    Point p1;
    Point p2;
    Point p3;
  };
  struct ArcSegment {
    Point start;
    Point end;
    Size size;
    dtype angle;
    bool sweep;
    bool large;
  };

  struct FontFormat {
    const wchar_t *family;
    dtype size;
    bool italic;
    bool bold;
    bool strikethrough;
    bool underline;
  };

  struct TextFormat {
    TextAlignHor halign;
    TextAlignVer valign;
    TextDirection direction;
    TextTrimming trimming;
    bool word_wrap;
    bool auto_width;
    bool auto_height;
  };

  class IResource : virtual public IBase {
    public:
      virtual IRender* render() const = 0;
      virtual Result reset() = 0;
  };

  class ITargetResource : virtual public IResource {
    public:
      virtual ITarget* target() const = 0;
  };

  class ISurfaceData : virtual public IResource {
    public:
      virtual Size size() const = 0;
      virtual uint stride() const = 0;
      virtual Result pixels(uint *buffer_size, void **data) const = 0;
  };
  class ISurface : virtual public IResource {
    public:
      virtual Result create(const PixelFormat format, const Size &size) = 0;
      virtual Result load_file(const char *file) = 0;
      virtual Result load_buffer(const char *buffer, ulong size) = 0;
      virtual Result save(const char *file, SurfaceType type) const = 0;

      virtual Size size() const = 0;
      virtual PixelFormat format() const = 0;
      virtual uint buffer_size() const = 0;
      virtual Result copy_pixels(uint stride, uint buffer_size, void *pixels) const = 0;
      virtual Result data(ISurfaceData **surface_data) = 0;
  };

  class IShape : virtual public IResource {
    public:
      virtual ShapeType type() const = 0;
  };

  class IShapeLine : virtual public IShape {
    public:
      virtual Result set(const Point &pt1, const Point &pt2) = 0;
      virtual Point point1() const = 0;
      virtual Point point2() const = 0;
  };
  class IShapePolyline : virtual public IShape {
    public:
      virtual Result set(const Point *pts, uint count) = 0;
      virtual Point* points() const = 0;
      virtual uint count() const = 0;
  };
  class IShapeBezier : virtual public IShape {
    public:
      virtual Result set(const BezierSegment &beizer) = 0;
      virtual Result set(const Point &pt0, const Point &pt1, const Point &pt2, const Point &pt3) = 0;
      virtual Point point0() const = 0;
      virtual Point point1() const = 0;
      virtual Point point2() const = 0;
      virtual Point point3() const = 0;
  };
  class IShapeArc : virtual public IShape {
    public:
      virtual Result set(const ArcSegment &arc) = 0;
      virtual Result set(const Point &start, const Point &end, const Size &size, dtype angle, bool sweep, bool large) = 0;
      virtual Point start() const = 0;
      virtual Point end() const = 0;
      virtual Size size() const = 0;
      virtual dtype angle() const = 0;
      virtual bool sweep() const = 0;
      virtual bool large() const = 0;
  };
  class IShapePolygon : virtual public IShape {
    public:
      virtual Result set(const Point *pts, uint count) = 0;
      virtual Point* points() const = 0;
      virtual uint count() const = 0;
  };
  class IShapeRect : virtual public IShape {
    public:
      virtual Result set(const Rect &rect, const Size &radius) = 0;
      virtual Rect rect() const = 0;
      virtual Size radius() const = 0;
  };
  class IShapeCircle : virtual public IShape {
    public:
      virtual Result set(const Point &center, dtype radius) = 0;
      virtual Point center() const = 0;
      virtual dtype radius() const = 0;
  };
  class IShapeEllipse : virtual public IShape {
    public:
      virtual Result set(const Point &center, const Size &radius) = 0;
      virtual Point center() const = 0;
      virtual Size radius() const = 0;
  };

  class IShapePath : virtual public IShape {
    public:
      virtual Result open(const FillMode mode) = 0;
      virtual Result close() = 0;

      virtual Result begin_figure(const Point &start_point) = 0;
      virtual Result end_figure(const FigureEnd figure_end) = 0;

      virtual Result add_line(const Point &point) = 0;
      virtual Result add_lines(const Point *points, uint count) = 0;
      virtual Result add_bezier(const Point &pt1, const Point &pt2, const Point &pt3) = 0;
      virtual Result add_arc(const Point &point, const Size &size, dtype angle, bool sweep, bool large) = 0;

      virtual bool point_in_path(const Point &point) const = 0;
  };

  class IShapeText : virtual public IShape {
    public:
      virtual Result set(const wchar_t *text, uint len, const Rect &rect
          , const FontFormat &font, const TextFormat &format) = 0;
      //
      virtual Rect rect() const = 0;
      //
      virtual const wchar_t* font_family() const = 0;
      virtual Result set_font_family(const wchar_t *family) = 0;
      virtual dtype font_size() const = 0;
      virtual Result set_font_size(dtype size) = 0;
      virtual bool font_italic() const = 0;
      virtual Result set_font_italic(bool italic) = 0;
      virtual bool font_bold() const = 0;
      virtual Result set_font_bold(bool bold) = 0;
      virtual bool font_strikethrough() const = 0;
      virtual Result set_font_strikethrough(bool strikethrough) = 0;
      virtual bool font_underline() const = 0;
      virtual Result set_font_underline(bool underline) = 0;
      //
      virtual TextAlignHor text_hor_align() const = 0;
      virtual Result set_text_hor_align(const TextAlignHor align) = 0;
      virtual TextAlignVer text_ver_align() const = 0;
      virtual Result set_text_ver_align(const TextAlignVer align) = 0;
      virtual TextDirection text_direction() const = 0;
      virtual Result set_text_direction(const TextDirection direction) = 0;
      virtual bool text_word_warp() const = 0;
      virtual Result set_text_word_warp(bool word_wrap) = 0;
  };

  class IStrokeStyle : virtual public IResource {
    public:
      virtual LineCap start_line_cap() const = 0;
      virtual LineCap end_line_cap() const = 0;
      virtual LineCap dash_line_cap() const = 0;
      virtual LineJoin line_join() const = 0;
      virtual dtype miterlimit() const = 0;
      virtual dtype dash_offset() const = 0;
      virtual uint dashes_count() const = 0;
      virtual Result dashes_data(dtype *dashes, uint count) const = 0;
  };

  class IBrush : virtual public ITargetResource {
    public:
      virtual dtype opacity() const = 0;
      virtual Result set_opacity(dtype _opacity) = 0;
      virtual Matrix transform() const = 0;
      virtual Result set_transform(const Matrix &matrix) = 0;
  };

  class ISolidColorBrush : virtual public IBrush {
    public:
      virtual Color color() const = 0;
      virtual Result set_color(const Color &color) = 0;
  };

  class IGradientStopCollection : virtual public ITargetResource {
    public:
      virtual uint count() const = 0;
      virtual Result data(GradientStop *stops) const = 0;
      virtual ExtendMode extend_mode() const = 0;
  };

  class ILinearGradientBrush : virtual public IBrush {
    public:
      virtual IGradientStopCollection* stop_collection() const = 0;
      virtual Point start_point() const = 0;
      virtual Result set_start_point(const Point& point) = 0;
      virtual Point end_point() const = 0;
      virtual Result set_end_point(const Point& point) = 0;
  };

  class IRadialGradientBrush : virtual public IBrush {
    public:
      virtual IGradientStopCollection* stop_collection() const = 0;
      virtual Point center() const = 0;
      virtual Result set_center(const Point& center) = 0;
      virtual Point offset() const = 0;
      virtual Result set_offset(const Point& offset) = 0;
      virtual dtype radius_x() const = 0;
      virtual Result set_radius_x(dtype radius_x) = 0;
      virtual dtype radius_y() const = 0;
      virtual Result set_radius_y(dtype radius_y) = 0;
  };

  class IBitmap : virtual public ITargetResource {
    public:
      virtual Result create(ISurface *surface) = 0;
      virtual Size size() const = 0;
  };

  class IBitmapBrush : virtual public IBrush {
    public:
      virtual Result bitmap(IBitmap **_bitmap) const = 0;
      virtual Result set_bitmap(IBitmap *_bitmap) = 0;
      virtual ExtendMode extend_mode_x() const = 0;
      virtual ExtendMode extend_mode_y() const = 0;
      virtual Result set_extend_mode_x(ExtendMode mode_x) = 0;
      virtual Result set_extend_mode_y(ExtendMode mode_y) = 0;
  };

  class ITarget : virtual public IResource {
    public:
      virtual Matrix transform() const = 0;
      virtual Result set_transform(const Matrix &matrix) = 0;

      virtual Result begin_draw() = 0;
      virtual Result end_draw() = 0;
      virtual Result clear(const Color *color = 0) = 0;
      virtual Result fill_shape(IShape *shape, IBrush *brush) = 0;
      virtual Result draw_shape(IShape *shape, IBrush *brush, dtype stroke_width = 1.f, IStrokeStyle *stroke_style = 0) = 0;
      virtual Result draw_bitmap(IBitmap *bitmap, const Rect *dst = 0, const Rect *src = 0) = 0;
      virtual Result draw_bitmap(IBitmap *bitmap, const Point &pt, const Rect *src = 0) = 0;

      virtual Result create_compatible_target(IBitmapTarget **target) = 0;
      virtual Result create_bitmap(IBitmap **bitmap) = 0;
      virtual Result create_bitmap_brush(IBitmapBrush **brush) = 0;
      virtual Result create_solid_color_brush(const Color &color, ISolidColorBrush **brush) = 0;
      virtual Result create_linear_gradient_brush(const LinearGradientBrushProperties &props
          , IGradientStopCollection *stop_collection, ILinearGradientBrush **brush) = 0;
      virtual Result create_radial_gradient_brush(const RadialGradientBrushProperties &props
          , IGradientStopCollection *stop_collection, IRadialGradientBrush **brush) = 0;
      virtual Result create_gradient_stop_collection(const GradientStop *stops, uint count, ExtendMode mode
          , IGradientStopCollection **stop_ollection) = 0;
  };

  class ISurfaceTarget : virtual public ITarget {
    public:
      virtual Result surface(ISurface **surface) const = 0;
  };
  
  class IWindowTarget : virtual public ITarget {
    public:
      virtual Result resize(Size size) = 0;
  };

  class IBitmapTarget : virtual public ITarget {
    public:
      virtual Result bitmap(IBitmap **_bitmap) = 0;
  };

  class IRender : virtual public IBase {
    public:
      virtual RenderType type() const = 0;
      virtual IFactory* factory() const = 0;
      virtual Result create_surface_target(const PixelFormat format, const Size &size, ISurfaceTarget **target) = 0;
      virtual Result create_window_target(void *handle, const Size &size, IWindowTarget **target) = 0;
      virtual Result create_shape_line(const Point &pt1, const Point &pt2, IShapeLine **shape) = 0;
      virtual Result create_shape_polyline(const Point *pts, uint count, IShapePolyline **shape) = 0;
      virtual Result create_shape_bezier(const BezierSegment &bezier, IShapeBezier **shape) = 0;
      virtual Result create_shape_arc(const ArcSegment &arc, IShapeArc **shape) = 0;
      virtual Result create_shape_polygon(const Point *pts, uint count, IShapePolygon **shape) = 0;
      virtual Result create_shape_rect(const Rect &rc, const Size &radius, IShapeRect **shape) = 0;
      virtual Result create_shape_circle(const Point &center, dtype radius, IShapeCircle **shape) = 0;
      virtual Result create_shape_ellipse(const Point &center, const Size &radius, IShapeEllipse **shape) = 0;
      virtual Result create_shape_path(IShapePath **shape) = 0;
      virtual Result create_shape_text(const wchar_t *text, uint len, const Rect &rect
          , const FontFormat &font, const TextFormat &format, IShapeText **shape) = 0;
      virtual Result create_stroke_style(const StrokeStyleProperties &props, const dtype *dashs, uint count
          , IStrokeStyle **stroke_style) = 0;
      virtual Result create_surface(ISurface **surface) = 0;
  };

} // end namespace c2d
} // end namespace cvs

#endif // __CANVAS_2D_H__